package com.zhuoyue.web.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zhuoyue.biz.core.api.dao.GroupMapper;
import com.zhuoyue.biz.core.api.domain.*;

import com.zhuoyue.biz.core.api.dto.rep.GroupQuickRepDTO;
import com.zhuoyue.biz.core.api.dto.rep.GroupRepDTO;
import com.zhuoyue.biz.core.api.dto.req.CommonGroupReq;
import com.zhuoyue.biz.core.api.service.*;
import com.zhuoyue.biz.core.api.service.impl.DeviceService;
import com.zhuoyue.common.aop.auth.CheckLogin;

import com.zhuoyue.common.aop.auth.User;

import com.zhuoyue.common.dto.ControllerResult;
import com.zhuoyue.common.utils.CodeUtil;
import com.zhuoyue.common.utils.Time;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import java.text.ParseException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wjming
 * @ClassName: AppLocalGroupsController
 * @Description:本地群组
 * @Date 2021/4/16 14:1
 */
@RestController
@Scope("prototype")
@RequestMapping("/api/group")
@Validated
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class AppLocalGroupsController {
    private final GroupMapper groupMapper;
    private final GroupService groupService;
    private final GroupQuickService groupQuickService;
    private final GroupDeviceRelationService groupDeviceRelationService;
    private final RedisTemplate redisTemplate;
    private final GatewayService gatewayService;
    private final DeviceService deviceService;
    private static final int GROUP_DEVICE = 64;
    private static final int REP_DTO = 3;
    private static final String DURATION = "duration";
    private static final String ADD = "add";
    private static final String DELETE = "delete";
    private static final int TIME_HOURS = 4;

    /**
     * 群组添加
     *
     * @param name
     * @param type 灯光类:light
     * @return
     */
    @PostMapping("/add")
    @CheckLogin
    public ControllerResult groupAdd(@Length(min = 1, max = 15, message = "不能超过15个字符") String name,
                                     @NotBlank(message = "设备类型不能为空") String type, String homeId,
                                     HttpServletRequest request) {
        User user = (User) request.getAttribute("user");
        log.info("request -> user:[{}_{}] [groupAdd] -> [name:{},type:{},homeId:{}]",
                user.getAccount(), user.getOrgCode(), name, type, homeId);
        //根据homeId查询网关信息
        GatewayDO gatewayDO = gatewayService.getByHomeId(homeId);
        if (gatewayDO == null) {
            return ControllerResult.toParamFail("请先添加网关");
        }
        //硬件版本号
        Integer hardwareVersionNumber = 2111;
        if (StringUtils.isNotEmpty(gatewayDO.getHardwareVersionNumber()) && Integer.parseInt(gatewayDO.getHardwareVersionNumber()) < hardwareVersionNumber) {
            return ControllerResult.toParamFail("网关版本低无法配置群组");
        }

        List<Group> groups = groupMapper.selectList(Wrappers.<Group>lambdaQuery().eq(Group::getGatewayMac, gatewayDO.getZigbeeMac()));
        List<Integer> groupsCodes = groups.stream().map(group -> Integer.parseInt(group.getCode())).collect(Collectors.toList());
        if (groups.size() >= GROUP_DEVICE) {
            return ControllerResult.toParamFail("最多只能添加64个群组");
        }
        int code = CodeUtil.getCode(groupsCodes, 65, "群组");
        String codeStr = String.format("%02d", code);

        Group group = new Group();
        group.setName(name);
        group.setType(type);
        group.setCode(codeStr);
        group.setHomeId(homeId);
        //新增网关信息
        group.setGatewayMac(gatewayDO.getZigbeeMac());
        int insert = groupMapper.insert(group);
        if (insert < 1) {
            return ControllerResult.toParamFail("群组信息添加失败");
        }
        Group group1 = groupMapper.selectById(group.getId());
        GroupRepDTO groupRepDTO = new GroupRepDTO();
        BeanUtils.copyProperties(group1, groupRepDTO);
        log.info("result -> [groupAdd] -> [name:{},type:{},homeId:{}]", name, type, homeId);
        return ControllerResult.toReturnDataSuccess("成功", groupRepDTO);
    }


    /**
     * 群组列表信息
     *
     * @param homeId
     * @return
     */
    @GetMapping("/list")
    @CheckLogin
    public ControllerResult groupList(@RequestParam @NotBlank(message = "家庭ID不能为空") String homeId, HttpServletRequest request) {
        User user = (User) request.getAttribute("user");
        log.info("request -> user:[{}_{}] [groupList] -> [homeId:{}]", user.getAccount(), user.getOrgCode(), homeId);
        //根据homeId查找对应的gatewayId
        GatewayDO gatewayDO = gatewayService.getByHomeId(homeId);
        if (gatewayDO == null) {
            return ControllerResult.toFail("该家庭无网关");
        }
        List<GroupRepDTO> groupReps = groupService.selectByGroups(gatewayDO.getZigbeeMac());
        if (groupReps.size() < REP_DTO) {
            log.info("result -> [groupList] -> [groupRepDTOS:{}]", groupReps);
        } else {
            log.info("result -> [groupList] -> [groupRepDTOS:{}]", groupReps.stream().map(g -> g.getId()).collect(Collectors.toList()));
        }

        //使用gatewayId进行群组查询
        return ControllerResult.toReturnDataSuccess("获取成功", groupReps);
    }


    /**
     * 获取单个群组详情
     *
     * @param groupId
     * @return
     */
    @GetMapping("/group/details")
    @CheckLogin
    public ControllerResult groupDetails(@NotBlank(message = "家庭ID不能为空") String groupId) {
        GroupRepDTO groupReps = groupService.selectGroupsDetailsById(groupId);
        return ControllerResult.toReturnDataSuccess("获取成功", groupReps);
    }


    /**
     * 修改群组信息
     *
     * @param id
     * @param name
     * @param type
     * @return
     */
    @PutMapping("/update")
    @CheckLogin
    public ControllerResult updateGroup(@RequestParam @NotBlank(message = "家庭ID不能为空") String id, @Length(min = 1, max = 15, message = "不能超过15个字符") String name, String type,
                                        String action) {
        if (StringUtils.isNotEmpty(action) && action.indexOf(DURATION) == -1) {
            ControllerResult.toParamFail("duration字段不能为空");
        }
        Group build = Group.builder().name(StringUtils.isBlank(name) ? null : name).type(StringUtils.isBlank(type) ? null : type).action(action).build();
        build.setId(id);
        groupService.updateById(build);
        return ControllerResult.toReturnMessageSuccess("修改成功");
    }

    /**
     * 多设备添加或删除操作接口
     *
     * @Description: 既可以多设备添加也可以多设备删除，多设备添加type参数add，多设备删除type参数delete
     * @param: deviceId
     * @param: groupId
     * @param: type
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 13:33
     */
    @PostMapping("/device/set")
    @CheckLogin
    public ControllerResult groupDeviceControllerSet(@RequestParam(value = "deviceId") String deviceId,
                                                     @NotBlank(message = "群组ID不能为空") String groupId,
                                                     @NotBlank(message = "添加类型不能为空,添加type参数add，删除type参数delete") String type) {
        if (!ADD.equals(type) && !DELETE.equals(type)) {
            return ControllerResult.toParamFail("type不是指定类型:类型必须指定为：add或delete");
        }
        Group group = groupMapper.selectById(groupId.trim());
        if (group == null) {
            return ControllerResult.toParamFail("群组ID不正确");
        }

        List<String> deviceIds = JSON.parseArray(deviceId, String.class);
        groupService.createGroupDeviceRelation(deviceIds, group, type);
        return ControllerResult.toReturnMessageSuccess("正在配置设备请稍后");
    }

    /**
     * @Description:群组设备控制
     * @param: groupId
     * @param: mode
     * @param: delayTime
     * @param: duration
     * @param: brightness
     * @param: colorTemperature
     * @param: request
     * @return: com.zhuoyue.common.dto.ControllerResult
     * @author:wjming
     * @Date:2021/4/17 13:34
     */
    @PostMapping("/group/control")
    @CheckLogin
    public ControllerResult groupControl(@NotBlank(message = "群组ID不能为空") String groupId,
                                         @NotBlank(message = "控制模型不能为空") String mode,
                                         Integer delayTime, Integer duration, Integer brightness, Integer colorTemperature,
                                         Integer modeIndex, HttpServletRequest request) throws ParseException {

        User user = (User) request.getAttribute("user");
        if (user == null) {
            log.info("request ->[getLinkageListStartDeviceId] -> [groupId:{},mode:{},delayTime:{},duration:{},brightness:{},colorTemperature:{}]", groupId, mode, delayTime, duration, brightness == null ? "null" : brightness, colorTemperature == null ? "null" : colorTemperature);
        } else {
            log.info("request -> user:[{}_{}] [getLinkageListStartDeviceId] -> [groupId:{},mode:{},delayTime:{},duration:{},brightness:{},colorTemperature:{},modeIndex:{}]",
                    user.getAccount(), user.getOrgCode(), groupId, mode, delayTime, duration, brightness == null ? "null" : brightness,
                    colorTemperature == null ? "null" : colorTemperature, modeIndex == null ? "null" : modeIndex);
        }


        Group group = groupService.getById(groupId);
        if (group == null) {
            return ControllerResult.toParamFail("控制失败");
        }
        groupService.deviceControl(group, mode, delayTime, duration, brightness, colorTemperature, modeIndex);
        group.setCode("colorTemperature");
        return ControllerResult.toReturnMessageSuccess("控制命令已发送");
    }

    /**
     * 群组控制通用方法
     *
     * @param commonReq
     * @return
     * @throws ParseException
     */
    @PostMapping("/group/control/new")
    @CheckLogin
    public ControllerResult groupControl1(@RequestBody CommonGroupReq commonReq, HttpServletRequest request) throws ParseException {
        User user = (User) request.getAttribute("user");
        log.info("request -> [getLinkageListStartDeviceId] -> [commonReq:{}]",
                JSONObject.toJSONString(commonReq));
        Group group = groupService.getById(commonReq.getGroupId());
        if (group == null) {
            return ControllerResult.toParamFail("控制失败");
        }
        groupService.deviceControl(group, commonReq.getControlParam());
        return ControllerResult.toReturnMessageSuccess("控制命令已发送");
    }


    /**
     * 群组个性设置(增加和修改并用)
     *
     * @param id
     * @param groupId
     * @param name
     * @param duration
     * @param brightness
     * @param colorTemperature
     * @return
     */
    @PostMapping("/personality/set")
    @CheckLogin
    public ControllerResult groupQuickControllerSet(String id, @RequestParam @NotBlank(message = "设备mac不能为空") String groupId,
                                                    @RequestParam @NotBlank(message = "名称不能为空") String name,
                                                    Integer duration, Integer brightness, Integer colorTemperature) {
        GroupQuick build = GroupQuick.builder().groupId(groupId).name(name).duration(duration)
                .brightness(brightness).colorTemperature(colorTemperature).build();
        if (StringUtils.isNotEmpty(id)) {
            build.setId(id);
        }
        boolean b = groupQuickService.saveOrUpdate(build);
        if (!b) {
            return ControllerResult.toParamFail("操作失败");
        }
        GroupQuick groupQuick = groupQuickService.getById(build.getId());
        GroupQuickRepDTO groupQuickRepDTO = new GroupQuickRepDTO();
        BeanUtils.copyProperties(groupQuick, groupQuickRepDTO);
        return ControllerResult.toReturnDataSuccess("群组个性配置成功", groupQuickRepDTO);
    }


    /**
     * 双色温快捷删除
     *
     * @param id
     * @return
     * @throws Exception
     */
    @DeleteMapping("/quick/del")
    @CheckLogin
    public ControllerResult delGroupQuick(@RequestParam @NotBlank(message = "快捷ID不能为空") String id) throws Exception {
        groupQuickService.removeById(id);
        return ControllerResult.toReturnMessageSuccess("快捷设置删除成功");
    }

    /**
     * 删除群组并清空群组中设备的信息
     * 注:当前只能实现空群组删除，未能实现群组清空
     *
     * @param groupId
     * @return
     * @throws InterruptedException
     */
    @DeleteMapping("/del/group")
    @CheckLogin
    public ControllerResult delGroup(@RequestParam @NotBlank(message = "群组ID不能为空") String groupId) throws InterruptedException {
        Group group = groupMapper.selectById(groupId);
        groupService.deleteGroupAndGroupSet(group);
        return ControllerResult.toReturnMessageSuccess("群组删除成功");
    }

    /**
     * 删除单个群组中设备的信息
     */

    @DeleteMapping("/del/one/device")
    @CheckLogin
    public ControllerResult delGroupOneDevice(@RequestParam @NotBlank(message = "关系ID") String relationId) throws InterruptedException {
        GroupDeviceRelation byId = groupDeviceRelationService.getById(relationId);
        if (byId == null) {
            return ControllerResult.toParamFail("关系信息不存在");
        }
        //查询次设备在次网关下是否存在，如果存在按照正常方式发送在删除,如果不存在就直接删除当前关系
        Group group = groupMapper.selectById(byId.getGroupId());
        GatewayDO one = gatewayService.getOne(Wrappers.<GatewayDO>lambdaQuery().eq(GatewayDO::getHomeId, group.getHomeId()));
        DeviceDO one1 = deviceService.getOne(Wrappers.<DeviceDO>lambdaQuery()
                .eq(DeviceDO::getId, byId.getDeviceId())
                .eq(DeviceDO::getGatewayId, one.getId())
                .eq(DeviceDO::getLwbz, "0"));
        if (one1 == null) {
            groupDeviceRelationService.removeById(relationId);
            return ControllerResult.toReturnDataSuccess("群组中的设备删除成功", relationId);
        } else {
            Duration duration = Duration.between(one1.getSwitchTime(), LocalDateTime.now());
            //加上在这个判断的目的是防止设备如果坏掉了，无法收到回应消息就不能删除，如果超过4个小时无法收到消息就判断为是离线，群组中的离线设备可以删除
            if (duration.toHours() > TIME_HOURS) {
                groupDeviceRelationService.removeById(relationId);
                return ControllerResult.toReturnDataSuccess("群组中的设备删除成功", relationId);
            }
            groupService.deleteGroupAndDeviceRelation(byId);
            return ControllerResult.toReturnMessageSuccess("正在删除群组中的设备信息");
        }


    }

    /**
     * 获取群组延时
     *
     * @param groupId
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/delay/time")
    public ControllerResult delayTime(@RequestParam @NotBlank(message = "群组ID不能为空") String groupId) throws InterruptedException {

        Object delayTime = redisTemplate.opsForValue().get(groupId.trim() + "_delayTime");
        if (delayTime == null) {
            return ControllerResult.toParamFail("设备延时时间不存在或已失效");
        } else {
            Map<String, Object> time = new HashMap<>(2);
            time.put("nowTime", Time.toLongMilli(LocalDateTime.now()));
            time.put("delayTime", delayTime);
            return ControllerResult.toReturnDataSuccess("添加成功", time);
        }
    }


}
